/*
 * Copyright (C) 2012 Tomas Shestakov. <http://code.google.com/p/jmmo/>
 */

package jmmo.engine.gameactor

import jmmo.engine.property._
import jmmo.engine.multifacetedactor.{ActorRole, MultifacetedActor}

trait ObservableActor extends MultifacetedActor with ChildrenContainer {

  override val container = new TransparentModifiableContainerSupport with NoneIdentifiable

  import ObservableRequest.Action._

  override def receive = super.receive orElse {
    case request: ObservableValueRequest =>
      def doGet(obsVal: ObservableValue[_]) { sender ! ObservableValueResponse(obsVal(), request.chain: _*) }
      def doSubscribe(obsVal: ObservableValue[_]) { obsVal.addChangeListener(ActorListener(sender, obsVal)) }

      container.observable(request.chain: _*).orNull match {
        case obsValue: ObservableValue[_] => request.action match {
          case Get => doGet(obsValue)
          case Subscribe => doSubscribe(obsValue)
          case Unsubscribe => obsValue.removeChangeListener(ActorListener(sender))
          case GetAndSubscribe =>
            doGet(obsValue)
            doSubscribe(obsValue)
        }
        case _ =>
      }

    case request: ObservableContainerRequest =>
      def doGet(cont: ObservableContainer) { sender ! ObservableContainerResponse(cont.serializedCopy(), request.chain: _*) }
      def doSubscribe(cont: ObservableContainer) { cont.addChangeListener(ActorListener(sender, cont)) }

      container.observable(request.chain: _*).orNull match {
        case obsCont: ObservableContainer => request.action match {
          case Get => doGet(obsCont)
          case Subscribe => doSubscribe(obsCont)
          case Unsubscribe => obsCont.removeChangeListener(ActorListener(sender))
          case GetAndSubscribe =>
            doGet(obsCont)
            doSubscribe(obsCont)
        }
        case _ =>
      }

    case request: FilteredObservableContainerRequest =>
      def doGet(cont: ObservableContainer) { sender ! ObservableContainerResponse(cont.serializedCopy(request.obsFilter), request.chain: _*) }
      def doSubscribe(cont: ObservableContainer) { cont.addChangeListener(ActorListener(sender, cont, request.eventFilter, request.obsFilter), request.obsFilter) }

      container.observable(request.chain: _*).orNull match {
        case obsCont: ObservableContainer => request.action match {
          case Get => doGet(obsCont)
          case Subscribe => doSubscribe(obsCont)
          case Unsubscribe => obsCont.removeChangeListener(ActorListener(sender))
          case GetAndSubscribe =>
            doGet(obsCont)
            doSubscribe(obsCont)
        }
        case _ =>
      }
  }

  override def addRole(role: ActorRole) {
    super.addRole(role)
    role match {
      case observable: Observable => container.addObservable(observable)
      case _ =>
    }
  }

  override def removeRole(role: ActorRole) {
    super.removeRole(role)
    role match {
      case observable: Observable => container.removeObservable(observable)
      case _ =>
    }
  }
}
